#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <errno.h>

#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"

#include "tpm2_value.h"
#include "tpm2_base_structs.h"
#include "tpm2_structure.h"

#include "tpm2_global.h"
#include "tpm2_command.h"
#include "vtcm_alg.h"

#include "tpm2_pcr.h"

int proc_tpm2_PCR_Read(void *sub_proc, void *recv_msg);
int proc_tpm2_PCR_Extend(void *sub_proc, void *recv_msg);
int proc_tpm2_PCR_getRandom(void *sub_proc, void *recv_msg);
//static int proc_tpm2_pcrreset(sub_proc, recv_msg);

int tpm2_pcr_init(void *sub_proc, void *para)
{
    int i, j;

    PCR *s_pcrs;
    TPM2_CUBE_GLOBAL *tpm2_global_data;
    tpm2_global_data = proc_share_data_getpointer();
    if (tpm2_global_data == NULL)
        return -EINVAL;
    s_pcrs = &tpm2_global_data->s_pcrs;

    for (i = 0; i < IMPLEMENTATION_PCR; i++)
    {
        Memset(s_pcrs[i].sm3_256Pcr, 0, SM3_256_DIGEST_SIZE);
        //将s_pcrs[i].sm3_256Pcr中当前位置后面的SM3_256_DIGEST_SIZE个字节用0 替换并返回 s_pcrs[i].sm3_256Pcr 。
    }
    ex_module_setpointer(sub_proc, s_pcrs); //为子模块设置指针上下文

    return 0;
}

int tpm2_pcr_start(void *sub_proc, void *para)
{
    int ret;
    int retval;
    void *recv_msg;
    void *context;
    int i;
    int type;
    int subtype;
    BYTE uuid[DIGEST_SIZE];

    printf("tpm2_pcr module start!\n");

    while (1)
    {
        usleep(time_val.tv_usec);
        ret = ex_module_recvmsg(sub_proc, &recv_msg); //从通道中获取消息
        if (ret < 0)
            continue;
        if (recv_msg == NULL)
            continue;

        type = message_get_type(recv_msg);
        subtype = message_get_subtype(recv_msg);

        if ((type == TYPE(TPM2_IN)) && (subtype == SUBTYPE(TPM2_IN, PCR_Extend)))
        {
            proc_tpm2_PCR_Extend(sub_proc, recv_msg);
        }
        else if ((type == TYPE(TPM2_IN)) && (subtype == SUBTYPE(TPM2_IN, PCR_Read)))
        {
            proc_tpm2_PCR_Read(sub_proc, recv_msg);
        }
        else if ((type == TYPE(TPM2_IN)) && (subtype == SUBTYPE(TPM2_IN, GetRandom)))
        {
            proc_tpm2_GetRandom(sub_proc, recv_msg);
        }
    }

    return 0;
};

int proc_tpm2_GetRandom(void *sub_proc, void *recv_msg)
{
    printf("proc_tpm2_GetRandom : Start\n");
    int ret = 0;
    int i = 0;

    RECORD(TPM2_IN, GetRandom) * tpm2_in;
    RECORD(TPM2_OUT, GetRandom) * tpm2_out;
    ret = message_get_record(recv_msg, (void *)&tpm2_in, 0);
    if (ret < 0)
        return ret;
    if (tpm2_in == NULL)
        return -EINVAL;
    //output process
    void *command_template = memdb_get_template(TYPE_PAIR(TPM2_OUT, GetRandom));
    if (command_template == NULL)
    {
        return -EINVAL;
    }
    tpm2_out = Talloc(struct_size(command_template));
    if (tpm2_out == NULL)
        return -EINVAL;

    tpm2_out->tag = TPM_ST_NO_SESSIONS;
    tpm2_out->responseCode = 0;

    if (tpm2_in->bytesRequested > 512)
        tpm2_out->randomBytes.b.size = 512;
    else
        tpm2_out->randomBytes.b.size = tpm2_in->bytesRequested;

    tpm2_out->responseSize = sizeof(*tpm2_out) - sizeof(BYTE *) + tpm2_out->randomBytes.b.size; //-sizeof(BYTE *)是为什么

    tpm2_out->randomBytes.b.buffer = Talloc0(tpm2_out->randomBytes.b.size);
    if (tpm2_out->randomBytes.b.buffer == NULL)
        return -ENOMEM;
    ret = RAND_bytes(tpm2_out->randomBytes.b.buffer, tpm2_out->randomBytes.b.size);

    void *send_msg = message_create(TYPE_PAIR(TPM2_OUT, GetRandom), recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    message_add_record(send_msg, tpm2_out);

    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;
}

int proc_tpm2_PCR_Extend(void *sub_proc, void *recv_msg)
{

    int ret = 0;
    int i;
    printf("proc_tpm2_extend : Start \n");
    BYTE buffer[DIGEST_SIZE * 2];
    PCR *s_pcrs;
    RECORD(TPM2_IN, PCR_Extend) * tpm2_in;
    RECORD(TPM2_OUT, PCR_Extend) * tpm2_out;
    int pcr_size;
    BYTE *pcr;
    void *send_msg;
    int tpm2_no;
    int returnCode = 0;

    s_pcrs = ex_module_getpointer(sub_proc);
    ret = message_get_record(recv_msg, (void **)&tpm2_in, 0); //消息中获取记录项
    if (ret < 0)
        return ret;
    if (tpm2_in == NULL)
    {
        returnCode = -EINVAL;
        goto extend_out_proc;
    }

    if ((tpm2_in->pcrHandle < 0) || (tpm2_in->pcrHandle >= IMPLEMENTATION_PCR))
    {
        returnCode = -EINVAL;
        goto extend_out_proc;
    }

    pcr = s_pcrs[tpm2_in->pcrHandle].sm3_256Pcr;

    for (i = 0; i < tpm2_in->digests.count; i++)
    {
        Memcpy(buffer, pcr, DIGEST_SIZE);                                                                            //从pcr指向的位置拷贝DIGEST_SIZE个字节到buffer中
        vtcm_sm3(buffer + DIGEST_SIZE, 1, tpm2_in->digests.digests[i].b.buffer, tpm2_in->digests.digests[i].b.size); //输入消息中的摘要值写入缓冲区
        vtcm_sm3(pcr, 1, buffer, DIGEST_SIZE * 2);                                                                   //参数含义。把缓冲区的数据（pcr原有数据+新输入的摘要值）复制到pcr中
    }

extend_out_proc:
    tpm2_out = Talloc(sizeof(*tpm2_out));
    if (tpm2_out == NULL)
        return -ENOMEM;
    tpm2_out->tag = TPM_ST_NO_SESSIONS;
    tpm2_out->responseSize = sizeof(tpm2_out);
    tpm2_out->responseCode = returnCode;

    send_msg = message_create(TYPE_PAIR(TPM2_OUT, PCR_Extend), recv_msg);
    if (send_msg == NULL)
        return -EINVAL;

    message_add_record(send_msg, tpm2_out);
    ret = ex_module_sendmsg(sub_proc, send_msg);

    return ret;
}

int proc_tpm2_PCR_Read(void *sub_proc, void *recv_msg)
{
    int ret = 0;
    int i;
    printf("proc_tpm2_pcrread : Start \n");
    BYTE buffer[DIGEST_SIZE * 2];
    PCR *s_pcrs;
    RECORD(TPM2_IN, PCR_Read) * tpm2_in;
    RECORD(TPM2_OUT, PCR_Read) * tpm2_out;
    int pcr_size;
    BYTE *pcr;
    void *send_msg;
    int tpm2_no;
    int returnCode = 0;

    s_pcrs = ex_module_getpointer(sub_proc); //获取子模块指针上下文
    ret = message_get_record(recv_msg, (void **)&tpm2_in, 0);
    if (ret < 0)
        return ret;
    if (tpm2_in == NULL)
    {
        returnCode = -EINVAL;
        goto pcr_read_out_proc;
    }

    /**************************************************************/
    //pcr_size=s_pcrs->pcr_size;？？？
    //pcr=s_pcrs[tpm2_in->pcrHandle].sm3_256Pcr;
    //TPML_PCR_SELECTION      selection;     //是tpm2_in->pcrSelectionIn、最后赋值给tpm2_out->pcrSelectionOut
    //TPMS_PCR_SELECTION      *select;        //查询列表，最后赋值给tpm2_out->pcrSelectionOut->pcrSelections
    //TPML_DIGEST             digest;        //摘要值，最后赋值out的pcrValues
    UINT32 cur_pcr; //当前pcr号
    //UINT32                   i;
    //selection=tpm2_in->pcrSelectionIn;
    //tpm2_out->pcrValues=digest;
    tpm2_out = Talloc(sizeof(*tpm2_out));
    if (tpm2_out == NULL)
        return -ENOMEM;
    tpm2_out->pcrSelectionOut.pcrSelections = Talloc0(sizeof(TPMS_PCR_SELECTION) * tpm2_in->pcrSelectionIn.count);
    printf("count : %d \n", tpm2_in->pcrSelectionIn.count);
    printf("sizeofSelect : %d \n", tpm2_in->pcrSelectionIn.pcrSelections[0].sizeofSelect);
    tpm2_out->pcrSelectionOut.pcrSelections[0].pcrSelect = Talloc0(tpm2_in->pcrSelectionIn.pcrSelections[0].sizeofSelect);
    tpm2_out->pcrSelectionOut.count = tpm2_in->pcrSelectionIn.count;
    tpm2_out->pcrValues.digests = Talloc0(sizeof(TPM2B_DIGEST) * tpm2_in->pcrSelectionIn.count);
    tpm2_out->pcrValues.digests->b.buffer = Talloc0(sizeof(TPM2B) * tpm2_in->pcrSelectionIn.count);
    tpm2_out->pcrValues.count = 0;

    // Iterate through the list of PCR selection structures
    for (i = 0; i < tpm2_in->pcrSelectionIn.count; i++) //每个pcr查询都循环一次
    {
        // Point to the current selection
        //select = tpm2_in->pcrSelectionIn.pcrSelections[i]; // Point to the current selection
        /**FilterPcr(select); /**自定义函数**/ // Filter过滤 Clear out the bits for unimplemented PCR

        tpm2_out->pcrSelectionOut.pcrSelections[i].hash = tpm2_in->pcrSelectionIn.pcrSelections[i].hash;
        tpm2_out->pcrSelectionOut.pcrSelections[i].sizeofSelect = tpm2_in->pcrSelectionIn.pcrSelections[i].sizeofSelect;

        // Iterate through the selection
        for (cur_pcr = 0; cur_pcr < IMPLEMENTATION_PCR; cur_pcr++) //按照pcr序号从小到大依次对照
        {
            //IsPcrSelected(cur_pcr,select)
            //    {
            //        BOOL  selected;
            //        selected = (cur_pcr < IMPLEMENTATION_PCR&& ((select->pcrSelect[cur_pcr / 8]) & (1 << (cur_pcr % 8))) != 0);
            //        return selected;
            //    }
            //if(IsPcrSelected(cur_pcr,tpm2_in->pcrSelectionIn.pcrSelections[i]))  //自定义函数
            if ((cur_pcr < IMPLEMENTATION_PCR && ((tpm2_in->pcrSelectionIn.pcrSelections[i].pcrSelect[cur_pcr / 8]) & (1 << (cur_pcr % 8))) != 0)) //查询select列表中是否有cur_pcr  Is this PCR selected
            {
                // Check if number of digest exceed upper bound
                if (tpm2_out->pcrValues.count > 7) /**如果摘要值列表的数量大于7，清除当前查询位图的剩余位并跳出内循环**/
                {
                    // Clear rest of the current select bitmap
                    while (cur_pcr < IMPLEMENTATION_PCR && (cur_pcr / 8) < tpm2_in->pcrSelectionIn.pcrSelections[i].sizeofSelect) // do not round up!
                    {
                        // do not round up!
                        /*tpm2_out->pcrSelectionOut.pcrSelections[i].hash=tpm2_in->pcrSelectionIn.pcrSelections[i].hash;
                        tpm2_out->pcrSelectionOut.pcrSelections[i].sizeofSelect=tpm2_in->pcrSelectionIn.pcrSelections[i].sizeofSelect;*/
                        tpm2_out->pcrSelectionOut.pcrSelections[i].pcrSelect[cur_pcr / 8] &= (BYTE) ~(1 << (cur_pcr % 8)); /**tpm2_out**/ //pcrSelect为PCR的位图
                        cur_pcr++;
                    }
                    // Exit inner loop
                    break;
                }
                // Need the size of each digest
                //digest->digests[digest->count].t.size =CryptHashGetDigestSize(selection->pcrSelections[i].hash);
                //digest->digests[digest->count].size =CryptHashGetDigestSize(selection->pcrSelections[i].hash);//IBM代码定义函数CryptHashGetDigestSize(hashAlg)返回哈希函数对应的摘要值大小
                tpm2_out->pcrValues.digests[tpm2_out->pcrValues.count].b.size = DIGEST_SIZE; //DIGEST_SIZE还是SM3_256_DIGEST_SIZE???
                tpm2_out->pcrValues.digests[tpm2_out->pcrValues.count].b.buffer = Talloc0(tpm2_out->pcrValues.digests[tpm2_out->pcrValues.count].b.size);
                //pcr = GetPcrPointer(selection->pcrSelections[i].hash, cur_pcr);/**IBM代码定义函数GetPcrPointer()
                printf("cur_pcr : %d \n", cur_pcr);
                printf("cur_pcr : %d \n", cur_pcr);
                pcr = s_pcrs[cur_pcr].sm3_256Pcr; //pcr指向当前pcr序号所对应的摘要。Get pointer to the digest data for the bank
                /**pAssert(pcr != NULL);//断言**/
                // Add to the data to digest
                //MemoryCopy(digest->digests[digest->count].t.buffer,pcr,digest->digests[digest->count].t.size);
                Memcpy(tpm2_out->pcrValues.digests[tpm2_out->pcrValues.count].b.buffer, pcr, tpm2_out->pcrValues.digests[tpm2_out->pcrValues.count].b.size); //将当前pcr序号所对应的摘要写入输出消息的摘要值列表中
                tpm2_out->pcrValues.count++;
                printf("tpm2_out->pcrValues.count : %d \n", tpm2_out->pcrValues.count);
            }
        }
        // If we exit inner loop because we have exceed the output upper bound
        if (tpm2_out->pcrValues.count > 7 && cur_pcr < IMPLEMENTATION_PCR) /**如果因摘要值列表的数量大于7而退出内循环，清除剩余查询列表**/
        {
            // Clear rest of the selection
            while (i < tpm2_out->pcrSelectionOut.count)
            {
                Memset(tpm2_out->pcrSelectionOut.pcrSelections[i].pcrSelect, 0, tpm2_in->pcrSelectionIn.pcrSelections[i].sizeofSelect); /**tpm2_out**/ //pcr位图剩余位置填0
                i++;
            }
            // exit outer loop
            break;
        }
    }
    //*pcrCounter = gr.pcrCounter;//pcrCounter为pcr种类记数器 /**global.h中定义STATE_RESET_DATA gr。gr结构中数据在关闭（状态）时保存并在后续启动（任何）时恢复**/

    /************************************************************/

pcr_read_out_proc:

    tpm2_out->tag = TPM_ST_NO_SESSIONS; //设置tpm2_out_PCR_Read的参数
    tpm2_out->responseSize = sizeof(tpm2_out);
    tpm2_out->responseCode = returnCode;

    tpm2_out->pcrUpdateCounter = tpm2_in->pcrSelectionIn.count; /**pcr更新计数器,每次改变都需要更新，需要存储**/

    send_msg = message_create(TYPE_PAIR(TPM2_OUT, PCR_Read), recv_msg);
    if (send_msg == NULL)
        return -EINVAL;
    message_add_record(send_msg, tpm2_out);
    ret = ex_module_sendmsg(sub_proc, send_msg);

    return ret;
}
